﻿using GalaSoft.MvvmLight;
using RestaurantBooker.Web.Data;
using GalaSoft.MvvmLight.Command;
using RestaurantBooker.Model;
using System;
using RestaurantBooker.View;
using System.Collections.ObjectModel;

namespace RestaurantBooker.ViewModel
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm/getstarted
    /// </para>
    /// </summary>
    public class BookerPageViewModel : ViewModelBase
    {
        #region Properties



        /// <summary>
        /// The <see cref="Orders" /> property's name.
        /// </summary>
        public const string OrdersPropertyName = "Orders";

        private ObservableCollection<Order> _orders = null;

        /// <summary>
        /// Gets the Orders property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<Order> Orders
        {
            get
            {
                return _orders;
            }

            set
            {
                if (_orders == value)
                    return;

                _orders = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(OrdersPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="FromDateTime" /> property's name.
        /// </summary>
        public const string FromDateTimePropertyName = "FromDateTime";

        private DateTime _fromDateTime= DateTime.Today;

        /// <summary>
        /// Gets the FromDateTime property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public DateTime FromDateTime
        {
            get
            {
                return _fromDateTime;
            }

            set
            {
                if (_fromDateTime == value)
                    return;

                _fromDateTime = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(FromDateTimePropertyName);
            }
        }

        /// <summary>
        /// The <see cref="ToDateTime" /> property's name.
        /// </summary>
        public const string ToDateTimePropertyName = "ToDateTime";

        private DateTime _toDateTime = DateTime.Today.AddDays(100).AddMilliseconds(-1);

        /// <summary>
        /// Gets the ToDateTime property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public DateTime ToDateTime
        {
            get
            {
                return _toDateTime ;
            }

            set
            {
                if (_toDateTime  == value)
                    return;

                _toDateTime  = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(ToDateTimePropertyName);
            }
        }
        
        public RoomVisualizerViewModel RoomVisualizerViewModel { get; set; }

        /// <summary>
        /// The <see cref="CurrentRoom" /> property's name.
        /// </summary>
        public const string CurrentRoomPropertyName = "CurrentRoom";

        private Room _currentRoom = null;

        /// <summary>
        /// Gets the CurrentRoom property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public Room CurrentRoom
        {
            get
            {
                return _currentRoom;
            }

            set
            {
                if (_currentRoom == value)
                {
                    return;
                }
                var oldValue = _currentRoom;
                _currentRoom = value;
                
                RefreshRoomData(_currentRoom);

                NewOrderCommand.RaiseCanExecuteChanged();
                ApplyOrderFilerCommand.RaiseCanExecuteChanged();

                // Update bindings, no broadcast
                RaisePropertyChanged(CurrentRoomPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CurrentOrder" /> property's name.
        /// </summary>
        public const string CurrentOrderPropertyName = "CurrentOrder";

        private Order _currentOrder = null;

        /// <summary>
        /// Gets the CurrentOrder property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public Order CurrentOrder
        {
            get
            {
                return _currentOrder;
            }

            set
            {
                if (_currentOrder == value)
                    return;

                _currentOrder = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(CurrentOrderPropertyName);
            }
        }
        #endregion

        #region Privat members
        private  OrderDetailsViewModel _orderDetailsViewModel = new OrderDetailsViewModel();
       
        private Lazy<View.OrderDetails> _lazyOrderDetails = null;
        private Lazy<ModalDialogContainer> _lazyNewCustomerDlg = null;

        #endregion

        private void RefreshRoomData(Room room)
        {
            this.RoomVisualizerViewModel.InitializeRoom(room);
        }

        /// <summary>
        /// Initializes a new instance of the BookerPageViewModel class.
        /// </summary>
        public BookerPageViewModel()
        {
            InitializeCommands();
            RoomVisualizerViewModel = new RoomVisualizerViewModel();

            InitializeLazyMembers();

            InitializeCommands();
        }

        private void InitializeLazyMembers()
        {
            _lazyOrderDetails = new Lazy<View.OrderDetails>(() =>
            {
                return new View.OrderDetails() { DataContext = _orderDetailsViewModel };
            });

            _lazyNewCustomerDlg = new Lazy<ModalDialogContainer>(() =>
            {
                var res = new ModalDialogContainer();
                res.Title = "New Order";
                res.DialogContent = _lazyOrderDetails.Value;
                res.OKButton.Content = "Create Order";
                res.ConfirmationResultProc = (dlgRes) =>
                    {
                        if (dlgRes.HasValue && dlgRes.Value)
                        {
                            // Insert new order
                            ServiceProcessor.ServiceProcessor.Instance.AddNewOrder(this.CurrentOrder, (error) =>
                                {
                                    if (error == null)
                                    {
                                        LoadOrders();      
                                    }
                                    else 
                                    {
                                        this.CurrentOrder = null;
                                        throw error;
                                    } 
                                });
                        }
                    };
            
                res.ValidationProc = (mdc) =>
                    {
                        if (_orderDetailsViewModel.CurrentOrder.Customer == null)
                        {
                            mdc.ErrorMessage = "Customer must be selected!";
                            return false;
                        }

                        return true;
                    };
                return res;
            });
        }


        private void LoadOrders()
        {
            ServiceProcessor.ServiceProcessor.Instance.GetOrderForPeriod(CurrentRoom.room_id, this.FromDateTime, this.ToDateTime,
                (error, list) =>
                {
                    if (error == null)
                    {
                        Orders = new ObservableCollection<Order>(list);
                    }
                    else
                    {
                        throw error;
                    }
                });
        }

        #region Commands

        public RelayCommand ApplyOrderFilerCommand { get; private set; }

        public RelayCommand NewOrderCommand { get; private set; }

        private void InitializeCommands()
        {
            ApplyOrderFilerCommand = new RelayCommand(() =>
                {
                    LoadOrders();
                },
                () =>
                {
                    return (CurrentRoom != null);
                });

            NewOrderCommand = new RelayCommand(() =>
                {
                    this.CurrentOrder = new Order() { order_start_time = DateTime.Now, order_duration = 120, order_person_count = 2 };
                    _orderDetailsViewModel.CurrentOrder = this.CurrentOrder;
                    _lazyNewCustomerDlg.Value.Show();
                },
                () =>
                {
                    return (CurrentRoom != null);
                });
        }
        #endregion

        public override void Cleanup()
        {
            // Clean own resources if needed

            base.Cleanup();
        }
    }
}